package com.freedy.concurrent.OptimisticLock;

import sun.misc.Unsafe;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 实现一个AtomicInteger
 * @author Freedy
 * @date 2021/4/23 22:54
 */
public class BuildAtomicInteger {
    public static void main(String[] args) throws Exception {
        for (int i = 0; i < 1000; i++) {
            Account.demo(new AccountCASWithMyAtomicInteger(10000));
        }
    }
}

class AccountCASWithMyAtomicInteger implements Account{
    private final MyAtomicInteger value;

    public AccountCASWithMyAtomicInteger(int value) {
        this.value = new MyAtomicInteger(value);
    }

    @Override
    public Integer getBalance() {
        return value.getValue();
    }

    @Override
    public void withdraw(Integer amount) {
        value.decrement(amount);
    }
}


class MyAtomicInteger{
    private static final Unsafe UNSAFE;
    private volatile int value;
    private static final long VALUE_OFFSET;

    static {
        UNSAFE=UnsafeGetter.getUnsafe();
        try {
            VALUE_OFFSET = UNSAFE.objectFieldOffset(MyAtomicInteger.class.getDeclaredField("value"));
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        }
    }

    public MyAtomicInteger() {
    }

    public MyAtomicInteger(int value) {
        this.value = value;
    }

    public void setValue(int value) {
        this.value = value;
    }

    public int getValue(){
        return value;
    }

    public void decrement(){
        decrement(1);
    }

    public void increment(){
        increment(1);
    }

    public void decrement(int amount){
        for (;;){
            int prev=value;
            int next=prev-amount;
            if (UNSAFE.compareAndSwapInt(this,VALUE_OFFSET,prev,next))
                break;
        }
    }

    public void increment(int amount){
        for (;;){
            int prev=value;
            int next=prev+amount;
            if (UNSAFE.compareAndSwapInt(this,VALUE_OFFSET,prev,next))
                break;
        }
    }

    public boolean compareAndSet(int expectedValue,int newValue){
        return UNSAFE.compareAndSwapInt(this, VALUE_OFFSET, expectedValue, newValue);
    }

}
